---
description: GraphQL Code Generator is a tool that generates code from your GraphQL schema and operations. It can generate TypeScript, Flow, Swift, Kotlin, and more.
---

import { Tabs, Callout } from '@theguild/components'

# Guide: React and Vue

GraphQL Code Generator provides a unified way to get TypeScript types from GraphQL operations for [most modern GraphQL clients and frameworks](#appendix-ii-compatibility).

This guide is built using the [Star wars films demo API](https://graphql.org/graphql/).

We will build a simple GraphQL front-end app using the following Query to fetch the list of Star Wars films:

```graphql
query allFilmsWithVariablesQuery($first: Int!) {
  allFilms(first: $first) {
    edges {
      node {
        ...FilmItem
      }
    }
  }
}
```

and its `FilmItem` Fragment definition:

```graphql
fragment FilmItem on Film {
  id
  title
  releaseDate
  producers
}
```

<Callout type="info">

All the below code examples are available in our [repository `examples` folder](https://github.com/dotansimha/graphql-code-generator/blob/master/examples).

</Callout>

## Installation

For most GraphQL clients and frameworks (React, Vue), install the following packages:

```sh npm2yarn
npm install graphql
npm install --save-dev typescript @graphql-codegen/cli @parcel/watcher
```

<br />

Then provide the corresponding framework-specific configuration:

<Tabs items={['React project', 'Vue project']}>

<Tabs.Tab>

```ts filename="codegen.ts" {5}
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  schema: 'https://graphql.org/graphql/',
  documents: ['src/**/*.tsx'],
  ignoreNoDocuments: true, // for better experience with the watcher
  generates: {
    './src/gql/': {
      preset: 'client'
    }
  }
}

export default config
```

</Tabs.Tab>

<Tabs.Tab>

```ts filename="codegen.ts" {1, 5, 9-11}
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  schema: 'https://graphql.org/graphql/',
  documents: ['src/**/*.vue'],
  ignoreNoDocuments: true, // for better experience with the watcher
  generates: {
    './src/gql/': {
      preset: 'client',
      config: {
        useTypeImports: true
      }
    }
  }
}

export default config
```

</Tabs.Tab>

</Tabs>

> **Note**: For React Query, please refer to our [dedicated guide](/docs/guides/react-query).

<br />

## Writing GraphQL Queries

First, start GraphQL Code Generator in watch mode:

```sh npm2yarn
npm run graphql-codegen --watch
```

_Using GraphQL Code Generator will type your GraphQL Query and Mutations as you write them ⚡️_

Now, we can start implementing our first query with the `graphql()` function, generated in `src/gql/`:

<Tabs items={['React Apollo', 'React Query', 'React URQL', 'Vue URQL', 'Vue Apollo']}>

<Tabs.Tab>

```ts filename="src/App.tsx" {6,8-18,22}
import React from 'react'
import { useQuery } from '@apollo/client'

import './App.css'
import Film from './Film'
import { graphql } from '../src/gql'

const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ `
  query allFilmsWithVariablesQuery($first: Int!) {
    allFilms(first: $first) {
      edges {
        node {
          ...FilmItem
        }
      }
    }
  }
`)

function App() {
  // `data` is typed!
  const { data } = useQuery(allFilmsWithVariablesQueryDocument, { variables: { first: 10 } })
  return (
    <div className="App">
      {data && <ul>{data.allFilms?.edges?.map((e, i) => e?.node && <Film film={e?.node} key={`film-${i}`} />)}</ul>}
    </div>
  )
}

export default App
```

</Tabs.Tab>

<Tabs.Tab>

```ts filename="src/App.tsx" {7, 8-18, 23-27}
import React from 'react'
import request from 'graphql-request'
import { useQuery } from '@tanstack/react-query'

import './App.css'
import Film from './Film'
import { graphql } from '../src/gql'

const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ `
  query allFilmsWithVariablesQuery($first: Int!) {
    allFilms(first: $first) {
      edges {
        node {
          ...FilmItem
        }
      }
    }
  }
`)

function App() {
  // `data` is typed!
  const { data } = useQuery(['films'], async () =>
    request('https://graphql.org/graphql/', allFilmsWithVariablesQueryDocument, {
      first: 10 // variables are typed too!
    })
  )

  return (
    <div className="App">
      {data && <ul>{data.allFilms?.edges?.map((e, i) => e?.node && <Film film={e?.node} key={`film-${i}`} />)}</ul>}
    </div>
  )
}

export default App
```

</Tabs.Tab>

<Tabs.Tab>

```ts filename="src/App.tsx" {6,8-18,22-27}
import React from 'react'
import { useQuery } from 'urql'

import './App.css'
import Film from './Film'
import { graphql } from '../src/gql'

const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ `
  query allFilmsWithVariablesQuery($first: Int!) {
    allFilms(first: $first) {
      edges {
        node {
          ...FilmItem
        }
      }
    }
  }
`)

function App() {
  // `data` is typed!
  const [{ data }] = useQuery({
    query: allFilmsWithVariablesQueryDocument,
    variables: {
      // variables are typed too!
      first: 10
    }
  })

  return (
    <div className="App">
      {data && <ul>{data.allFilms?.edges?.map((e, i) => e?.node && <Film film={e?.node} key={`film-${i}`} />)}</ul>}
    </div>
  )
}

export default App
```

</Tabs.Tab>

<Tabs.Tab>

```vue filename="src/App.vue" {6,9-21,24}
<script setup lang="ts">
import { useQuery } from '@urql/vue'
import { computed } from 'vue'

import FilmItem from './components/FilmItem.vue'
import { graphql } from '../src/gql'

const { data } = useQuery({
  query: graphql(/* GraphQL */ `
    query allFilmsWithVariablesQuery($first: Int!) {
      allFilms(first: $first) {
        edges {
          node {
            ...FilmItem
          }
        }
      }
    }
  `),
  // variables are typed!
  variables: { first: 10 }
})
// `films` is typed!
const films = computed(() => data.value?.allFilms?.edges?.map(e => e?.node!))
</script>

<template>
  <ul>
    <li v-for="film of films"><FilmItem :film="film" /></li>
  </ul>
</template>
```

</Tabs.Tab>

<Tabs.Tab>

```vue filename="src/App.vue" {6,9-21,24}
<script setup lang="ts">
import { useQuery } from '@vue/apollo-composable'
import { computed } from 'vue'

import FilmItem from './components/FilmItem.vue'
import { graphql } from '../src/gql'

const { result } = useQuery(
  graphql(/* GraphQL */ `
    query allFilmsWithVariablesQuery($first: Int!) {
      allFilms(first: $first) {
        edges {
          node {
            ...FilmItem
          }
        }
      }
    }
  `),
  // variables are typed!
  { first: 10 }
)
// `films` is typed!
const films = computed(() => result.value?.allFilms?.edges?.map(e => e?.node!))
</script>

<template>
  <ul>
    <li v-for="film of films"><FilmItem :film="film" /></li>
  </ul>
</template>
```

</Tabs.Tab>

</Tabs>

<Callout type="info">

**Be cautious**, anonymous Queries and Mutations will be ignored.

</Callout>

Simply use the provided `graphql()` function (from `../src/gql/`) to define your GraphQL Query or Mutation, then, get instantly typed-variables and result just by passing your GraphQL document to your favorite client ✨

Let's now take a look at how to define our `<Film>` component using the `FilmItem` fragment and its corresponding TypeScript type.

## Writing GraphQL Fragments

As showcased [in one of our recent blog posts](https://www.the-guild.dev/blog/unleash-the-power-of-fragments-with-graphql-codegen), GraphQL Fragments help build better isolated and reusable UI components.

Let's look at the implementation of our `Film` UI component in React or Vue:

<Tabs items={['React (Apollo, React Query, URQL)', 'Vue (Apollo, URQL)']}>

<Tabs.Tab>

```ts filename="src/Film.tsx" {4-11,15,17}
import { FragmentType, useFragment } from './gql/fragment-masking'
import { graphql } from '../src/gql'

export const FilmFragment = graphql(/* GraphQL */ `
  fragment FilmItem on Film {
    id
    title
    releaseDate
    producers
  }
`)

const Film = (props: {
  /* `film` property has the correct type 🎉 */
  film: FragmentType<typeof FilmFragment>
}) => {
  const film = useFragment(FilmFragment, props.film)
  return (
    <div>
      <h3>{film.title}</h3>
      <p>{film.releaseDate}</p>
    </div>
  )
}

export default Film
```

</Tabs.Tab>

<Tabs.Tab>

```vue filename="src/components/FilmItem.vue" {5-12,14,17}
<script setup lang="ts">
import { graphql } from '.../src/gql'
import { type FragmentType, useFragment } from '../gql/fragment-masking'

const FilmFragment = graphql(/* GraphQL */ `
  fragment FilmItem on Film {
    id
    title
    releaseDate
    producers
  }
`)
const props = defineProps<{
  film: FragmentType<typeof FilmFragment>
}>()
// `filmObj` is typed!
const filmObj = useFragment(FilmFragment, props.film)
</script>

<template>
  <div>
    <h3>{{ filmObj.title }}</h3>
    <p>{{ filmObj.releaseDate }}</p>
  </div>
</template>
```

</Tabs.Tab>

</Tabs>

<Callout type="info">

Examples for SWR (React), `graphql-request` and Villus (Vue) are available in our [repository `examples` folder](https://github.com/dotansimha/graphql-code-generator/blob/master/examples).

</Callout>

You will notice that our `<FilmItem>` component leverages 2 imports from our generated code (from `../src/gql`): the `FragmentType<T>` type helper and the `useFragment()` function.

- we use `FragmentType<typeof FilmFragment>` to get the corresponding Fragment TypeScript type
- later on, we use `useFragment()` to retrieve the `film` property

Leveraging `FragmentType<typeof FilmFragment>` and `useFragment()` helps keep your UI component isolated and avoids inheriting the parent GraphQL Query's typings.

<br />

> By using GraphQL Fragments, you are explicitly declaring your UI component's data dependencies and safely accessing only the data it needs.

<br />

Finally, unlike most GraphQL Client setups, you don't need to append the Fragment definition document to the related Query. You simply need to reference it in your GraphQL Query, as shown below:

```ts {6}
const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ `
  query allFilmsWithVariablesQuery($first: Int!) {
    allFilms(first: $first) {
      edges {
        node {
          ...FilmItem
        }
      }
    }
  }
`)
```

<br />

Congratulations, you now have the best GraphQL front-end experience with fully-typed Queries and Mutations!

From simple Queries to more advanced Fragments-based ones, GraphQL Code Generator has you covered with a simple TypeScript configuration file, and without impact on your application bundle size! 🚀

**What's next?**

To get the best GraphQL development experience, we recommend installing the [GraphQLSP](https://github.com/0no-co/GraphQLSP) package to get:

- syntax highlighting
- autocomplete suggestions
- validation against schema
- quick-info on hover

![GraphQLSP](/assets/pages/docs/guides/react-vue/graphqlsp.png)

`GraphQLSP`s a TypeScript LSP plugin for GraphQL, to get it working, we need to add the following to your `tsconfig.json`
after installing the package (`npm i -D @0no-co/graphqlsp`):

```json filename="tsconfig.json"
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "@0no-co/graphqlsp",
        "schema": "./schema.graphql"
      }
    ]
  }
}
```

Last but not least you need to ensure that when you're using `VSCode` that the workspace version of TS is used, the following
config will make a prompt appear to switch it when visiting a TS file

```json filename=".vscode/settings.json"
{
  "typescript.tsdk": "node_modules/typescript/lib",
  "typescript.enablePromptUseWorkspaceTsdk": true
}
```

Also, make sure to follow GraphQL best practices by using [`graphql-eslint`](https://github.com/B2o5T/graphql-eslint) and the [ESLint VSCode extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) to visualize errors and warnings inlined in your code correctly.

Feel free to continue playing with this demo project, available in all flavors, in our [repository `examples` folder](https://github.com/dotansimha/graphql-code-generator/blob/master/examples).

<br />

---

<br />

## Config API

The `client` preset allows the following `config` options:

- [`scalars`](/plugins/typescript/typescript#scalars): Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type.
- [`defaultScalarType`](/plugins/typescript/typescript#defaultscalartype): Allows you to override the type that unknown `scalars` will have. Defaults to `any`.
- [`strictScalars`](/plugins/typescript/typescript#strictscalars): If `scalars` are found in the schema that are not defined in scalars an error will be thrown during codegen.
- [`namingConvention`](/plugins/typescript/typescript#namingconvention): Available case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst`.
- [`useTypeImports`](/plugins/typescript/typescript#usetypeimports): Will use `import type {}` rather than `import {}` when importing only types. This gives compatibility with TypeScript's [`"importsNotUsedAsValues": "error"`](https://www.typescriptlang.org/tsconfig#importsNotUsedAsValues) option.
- [`skipTypename`](/plugins/typescript/typescript#skiptypename): Does not add `__typename` to the generated types, unless it was specified in the selection set.
- [`arrayInputCoercion`](/plugins/typescript/typescript-operations#arrayinputcoercion): The [GraphQL spec](https://spec.graphql.org/draft/#sel-FAHjBJFCAACE_Gh7d) allows arrays and a single primitive value for list input. This allows to deactivate that behavior to only accept arrays instead of single values.
- [`enumsAsTypes`](/plugins/typescript/typescript#enumsastypes): Generates enum as TypeScript string union `type` instead of an `enum`. Useful if you wish to generate `.d.ts` declaration file instead of `.ts`, or if you want to avoid using TypeScript enums due to bundle size concerns.
- [`enumsAsConst`](/plugins/typescript/typescript#enumsasconst): Generates enum as TypeScript const assertions instead of enum. This can even be used to enable enum-like patterns in plain JavaScript code if you choose not to use TypeScript’s enum construct.
- [`enumValues`](/plugins/typescript/typescript#enumvalues): Overrides the default value of enum values declared in your GraphQL schema. You can also map the entire enum to an external type by providing a string that of module#type.
- [`nonOptionalTypename`](/plugins/typescript/typescript#nonoptionaltypename): Automatically adds `__typename` field to the generated types, even when they are not specified in the selection set, and makes it non-optional.
- [`avoidOptionals`](/plugins/typescript/typescript#avoidoptionals): This will cause the generator to avoid using TypeScript optionals (`?`) on types.

<br />

---

<br />

## Appendix I: React Query with a custom fetcher setup

The use of `@tanstack/react-query` along with `graphql-request@^5` is highly recommended due to GraphQL Code Generator integration with `graphql-request@^5`.

Create a file with the following helper function within your project:

```ts filename="useGraphQL helper function"
import request from 'graphql-request'
import { type TypedDocumentNode } from '@graphql-typed-document-node/core'
import { useQuery, type UseQueryResult } from '@tanstack/react-query'

export function useGraphQL<TResult, TVariables>(
  document: TypedDocumentNode<TResult, TVariables>,
  ...[variables]: TVariables extends Record<string, never> ? [] : [TVariables]
): UseQueryResult<TResult> {
  return useQuery([(document.definitions[0] as any).name.value, variables], async ({ queryKey }) =>
    request('https://graphql.org/graphql/', document, queryKey[1] ? queryKey[1] : undefined)
  )
}
```

Then write type-safe code like the following:

```ts filename="Application Code"
import { useGraphQL } from './use-graphql.js'
import { graphql } from './generated/gql.js'

const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ `
  query allFilmsWithVariablesQuery($first: Int!) {
    allFilms(first: $first) {
      edges {
        node {
          title
        }
      }
    }
  }
`)

function App() {
  // `data` is properly typed, inferred from `allFilmsWithVariablesQueryDocument` type
  const { data } = useGraphQL(
    allFilmsWithVariablesQueryDocument,
    // variables are also properly type-checked.
    { first: 10 }
  )

  // ... further component code
}
```

In case you do not want to use `graphql-request` with `@tanstack/react-query`, you can write and type your own custom fetcher function.

GraphQL Code Generator, via the `client` preset, generates GraphQL documents similar to the following:

```ts
const query: TypedDocumentNode<{ greetings: string }, never | Record<any, never>> = parse(/* GraphQL */ `
  query greetings {
    greetings
  }
`)
```

A `TypedDocumentNode<R, V>` type carry 2 Generic arguments: the type of the GraphQL result `R` and the type of the GraphQL operation variables `V`.

To implement your own React Query fetcher while preserving the GraphQL document type inference, it should implement a function signature that extract the result type and use it as a return type, as showcased below:

```ts filename="Custom fetcher function and useGraphQL hook implementation"
import { type TypedDocumentNode } from '@graphql-typed-document-node/core'
import { useQuery, type UseQueryResult } from '@tanstack/react-query'
import { print, type ExecutionResult } from 'graphql'

/** Your custom fetcher function */
async function customFetcher<TResult, TVariables>(
  url: string,
  document: TypedDocumentNode<TResult, TVariables>,
  ...[variables]: TVariables extends Record<string, never> ? [] : [TVariables]
): Promise<TResult> {
  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'content-type': 'application/json'
    },
    body: JSON.stringify({
      query: print(document),
      variables
    })
  })
  if (response.status !== 200) {
    throw new Error(`Failed to fetch: ${response.statusText}. Body: ${await response.text()}`)
  }

  return await response.json()
}

export function useGraphQL<TResult, TVariables>(
  document: TypedDocumentNode<TResult, TVariables>,
  ...[variables]: TVariables extends Record<string, never> ? [] : [TVariables]
): UseQueryResult<ExecutionResult<TResult>> {
  return useQuery([(document.definitions[0] as any).name.value, variables], () =>
    customFetcher('https://graphql.org/graphql/', document, variables)
  )
}
```

Then write type-safe code like the following:

```ts filename="Application Code"
import { useGraphQL } from './use-graphql.js'
import { graphql } from './generated/gql.js'

const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ `
  query allFilmsWithVariablesQuery($first: Int!) {
    allFilms(first: $first) {
      edges {
        node {
          title
        }
      }
    }
  }
`)

function App() {
  // `data` is properly typed, inferred from `allFilmsWithVariablesQueryDocument` type
  const { data } = useGraphQL(
    allFilmsWithVariablesQueryDocument,
    // variables are also properly type-checked.
    { first: 10 }
  )

  // ... further component code
}
```

<br />

---

<br />

## Appendix II: Compatibility

GraphQL Code Generator `client` preset (`@graphql-codegen/client-preset`) is compatible with the following GraphQL clients and frameworks:

- **React**

  - `@apollo/client` (since `3.2.0`, not when using React Components (`<Query>`))
  - `@urql/core` (since `1.15.0`)
  - `@urql/preact` (since `1.4.0`)
  - `urql` (since `1.11.0`)
  - `graphql-request` (since `5.0.0`)
  - `react-query` (with `graphql-request@5.x`)
  - `swr` (with `graphql-request@5.x`)

- **Vue**
  - `@vue/apollo-composable` (since `4.0.0-alpha.13`)
  - `villus` (since `1.0.0-beta.8`)
  - `@urql/vue` (since `1.11.0`)

If your stack is not listed above, please refer to other guides ([Angular](/docs/guides/angular), [Svelte](/docs/guides/svelte)) or to [our plugins directory](/plugins).
